package cn.aaalei.shorturl.service.impl;

import cn.aaalei.shorturl.mapper.UrlMapper;
import cn.aaalei.shorturl.pojo.UrlMapping;
import cn.aaalei.shorturl.service.ApiService;
import cn.aaalei.shorturl.utils.HexUtil;
import com.google.common.hash.Hashing;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class ApiServiceImpl implements ApiService {

    @Autowired
    private UrlMapper urlMapper;

    /**
     * 计算短链接
     * @param url
     * @return
     */
    @Override
    public String getShort(String url) throws UnsupportedEncodingException {
        List<String> hanziList = new ArrayList<String>();
        try {

            Pattern p = null;
            Matcher m = null;
            String value = null;
            p = Pattern.compile("([\u4e00-\u9fa5]+)"); // 汉字的在unicode编码的范围区域：\u4e00-\u9fa5
            m = p.matcher(url);
            while (m.find()) {
                value = m.group(0);
                hanziList.add(value); //先一个个匹配取出放在list集合中
            }
            for (String hanzi : hanziList) {
                url = url.replace(hanzi, URLEncoder.encode(hanzi, "UTF-8")); //再替换
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        //生成短链接  通过MurmurHash计算出Hash值 然后将10进制数字转化为62进制数字
        String shortUrl = HexUtil.encode(Hashing.murmur3_32().hashString(url, StandardCharsets.UTF_8).padToLong(),0);
        if(urlMapper.selectUrlMappingExist(shortUrl,url) != null){
            return shortUrl;
        }
        //比对数据库是否Hash冲突 如果发生冲突进行再次加密
        while (hashExist(shortUrl)){
            shortUrl = HexUtil.encode(Hashing.murmur3_32().hashString(shortUrl,StandardCharsets.UTF_8).padToLong(),0);
        }
        UrlMapping urlMapping = new UrlMapping();
        urlMapping.setShortUrl(shortUrl);
        urlMapping.setFormerUrl(url);
        urlMapper.addUrlMapping(urlMapping);
        return shortUrl;
    }

    /**
     * 二维码生成
     * @param url
     * @return
     * @throws WriterException
     * @throws IOException
     */
    @Override
    public String getQRCodeUrl(String url) throws WriterException, IOException {
        QRCodeWriter qrCodeWriter = new QRCodeWriter();
        //设置二维码图片宽高
        BitMatrix bitMatrix = qrCodeWriter.encode(url, BarcodeFormat.QR_CODE,200,200);
        //
        bitMatrix = deleteWhite(bitMatrix);
        // 写到输出流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        MatrixToImageWriter.writeToStream(bitMatrix, "PNG", outputStream);
        //转换为base64
        Base64.Encoder encoder = Base64.getEncoder();
        String qrCodeUrl = "data:image/jpeg;base64," + encoder.encodeToString(outputStream.toByteArray());
        return qrCodeUrl;
    }

    /**
     * 解决
     * @param matrix
     * @return
     */
    private static BitMatrix deleteWhite(BitMatrix matrix) {
        int[] rec = matrix.getEnclosingRectangle();
        int resWidth = rec[2] + 1;
        int resHeight = rec[3] + 1;

        BitMatrix resMatrix = new BitMatrix(resWidth, resHeight);
        resMatrix.clear();
        for (int i = 0; i < resWidth; i++) {
            for (int j = 0; j < resHeight; j++) {
                if (matrix.get(i + rec[0], j + rec[1]))
                    resMatrix.set(i, j);
            }
        }
        return resMatrix;
    }

    /**
     * 判断hash是否在数据库已经存在了
     * @param hash
     * @return
     */
    private boolean hashExist(String hash){
        UrlMapping urlMapping = urlMapper.selectUrlMapping(hash);
        if(urlMapping != null){
            return true;
        }
        return false;
    }
}
